package com.ruoyi.generator.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.ColumnParam;
import com.ruoyi.common.core.domain.GenTableColumn;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.json.JsonMap;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.mapper.TbMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 通用动态表操作
 *
 * @author he
 * @date 2021-04-16
 */
@Service
@Slf4j
public class TbService {

    @Autowired
    private TbMapper tbMapper;

    private final static String ID_COLUMN_NAME = "id";

    public static final String[] IGNORE_UPDATE_COLUMN_NAME = {"id", "create_by", "create_time", "update_by", "update_time", "deleted"};

    /**
     * 获取所有字段数据
     *
     * @param tbName
     * @param ids
     * @return
     */
    public List<Map<String, Object>> getByIdsLogic(String tbName, String ids) {
        Long[] idColValue = Convert.toLongArray(ids);
        return tbMapper.getByIdsLogic(tbName, null, ID_COLUMN_NAME, idColValue);
    }

    /**
     * 获取指定字段数据
     *
     * @param tbName
     * @param columnNames
     * @param ids
     * @return
     */

    public List<Map<String, Object>> getByIdsLogic(String tbName, List<String> columnNames, String ids) {
        Long[] idColValue = Convert.toLongArray(ids);
        return tbMapper.getByIdsLogic(tbName, columnNames, ID_COLUMN_NAME, idColValue);
    }


    public List<Map<String, Object>> getList(String tbName, List<GenTableColumn> columns) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, null, columns, false, null);
        return list;
    }


    public Page getPage(String tbName, List<GenTableColumn> columns, Page page) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, null, columns, false, page);
        page.setRecords(list);
        return page;
    }


    public List<Map<String, Object>> getList(String tbName, List<String> selectColumns, List<GenTableColumn> whereColumns) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, selectColumns, whereColumns, false, null);
        return list;
    }


    public Page getPage(String tbName, List<String> selectColumns, List<GenTableColumn> whereColumns, Page page) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, selectColumns, whereColumns, false, page);
        page.setRecords(list);
        return page;
    }


    public List<Map<String, Object>> getListColumnQuery(String tbName, List<String> selectColumns, List<ColumnParam> columns) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, selectColumns, columns, false, null);
        return list;
    }


    public Page<Map<String, Object>> getPageColumnQuery(String tbName, List<String> selectColumns, List<ColumnParam> columns, Page<Map<String, Object>> page) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, selectColumns, columns, false, page);
        page.setRecords(list);
        return page;
    }


    public List<Map<String, Object>> getListColumnQuery(String tbName, List<ColumnParam> columns) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, null, columns, false, null);
        return list;
    }


    public Page getPageColumnQuery(String tbName, List<ColumnParam> columns, Page page) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, null, columns, false, page);
        page.setRecords(list);
        return page;
    }


    public List<Map<String, Object>> getListLogic(String tbName, List<GenTableColumn> queryColumns) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, null, queryColumns, true, null);
        return list;
    }


    public Page getPageLogic(String tbName, List<GenTableColumn> queryColumns, Page page) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, null, queryColumns, true, page);
        page.setRecords(list);
        return page;
    }


    public List<Map<String, Object>> getListLogic(String tbName, List<String> selectColumns, List<GenTableColumn> queryColumns) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, selectColumns, queryColumns, true, null);
        return list;
    }


    public Page getPageLogic(String tbName, List<String> selectColumns, List<GenTableColumn> queryColumns, Page page) {
        List<Map<String, Object>> list = tbMapper.getList(tbName, selectColumns, queryColumns, true, page);
        page.setRecords(list);
        return page;
    }


    public List<Map<String, Object>> getListColumnQueryLogic(String tbName, List<ColumnParam> columns) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, null, columns, true, null);
        return list;
    }


    public Page getPageColumnQueryLogic(String tbName, List<ColumnParam> columns, Page page) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, null, columns, true, page);
        page.setRecords(list);
        return page;
    }


    public List<Map<String, Object>> getListColumnQueryLogic(String tbName, List<String> selectColumns, List<ColumnParam> columns) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, selectColumns, columns, true, null);
        return list;
    }


    public Page<Map<String, Object>> getPageColumnQueryLogic(String tbName, List<String> selectColumns, List<ColumnParam> columns, Page<Map<String, Object>> page) {
        List<Map<String, Object>> list = tbMapper.getListByColumnQuery(tbName, selectColumns, columns, true, page);
        page.setRecords(list);
        return page;
    }


    public Map<String, Object> getOne(String tbName, List<String> selectColumns, Long idVal) {
        Map<String, Object> list = tbMapper.getOneByField(tbName, selectColumns, ID_COLUMN_NAME, idVal, false);
        return list;
    }


    public Map<String, Object> getOne(String tbName, Long idVal) {
        Map<String, Object> list = tbMapper.getOneByField(tbName, null, ID_COLUMN_NAME, idVal, false);
        return list;
    }


    public Map<String, Object> getOne(String tbName, String idVal) {
        Map<String, Object> list = tbMapper.getOneByField(tbName, null, ID_COLUMN_NAME, idVal, false);
        return list;
    }


    public Map<String, Object> getOne(String tbName, String field, Object val) {
        Map<String, Object> list = tbMapper.getOneByField(tbName, null, field, val, false);
        return list;
    }


    public Map<String, Object> getOneLogic(String tbName, Long idVal) {
        Map<String, Object> list = tbMapper.getOneByField(tbName, null, ID_COLUMN_NAME, idVal, true);
        return list;
    }


    public Map<String, Object> getOneLogic(String tbName, List<String> selectColumns, Long idVal) {
        Map<String, Object> list = tbMapper.getOneByField(tbName, selectColumns, ID_COLUMN_NAME, idVal, true);
        return list;
    }


    public int removeAll(String tbName, String ids) {
        Long[] dictIds = Convert.toLongArray(ids);
        int i = tbMapper.deleteByIds(tbName, ID_COLUMN_NAME, dictIds);
        return i;
    }

    /**
     * 删除并备份
     *
     * @param tbName
     * @param ids
     * @return
     */

    @Transactional(rollbackFor = Exception.class)
    public int removeAllAndBackup(String tbName, String ids) {
        Long[] dictIds = Convert.toLongArray(ids);
        tbMapper.backupByIds(tbName, ID_COLUMN_NAME, dictIds, BusinessType.DELETE.ordinal());
        int i = tbMapper.deleteByIds(tbName, ID_COLUMN_NAME, dictIds);
        return i;
    }

    /**
     * 更新并备份
     *
     * @param tbName
     * @return
     */

    @Transactional(rollbackFor = Exception.class)
    public int updateAndBackupById(String tbName, JsonMap params, Map<String, GenTableColumn> genTableColumnMap) {
        Long id = params.getLong(ID_COLUMN_NAME);
        Long[] dictIds = {id};
        tbMapper.backupByIds(tbName, ID_COLUMN_NAME, dictIds, BusinessType.UPDATE.ordinal());
        int i = updateById(tbName, params, genTableColumnMap);
        return i;
    }


    public int removeAllLogic(String tbName, String ids) {
        Long[] dictIds = Convert.toLongArray(ids);
        int i = tbMapper.deleteByIdsLogic(tbName, ID_COLUMN_NAME, dictIds);
        return i;
    }


    public List<GenTableColumn> getUpdateColumns(Map<String, Object> objectMap, Map<String, GenTableColumn> genTableColumnMap) {
        for (String col : IGNORE_UPDATE_COLUMN_NAME) {
            objectMap.remove(col);
        }
        List<GenTableColumn> columns = new ArrayList<>();
        for (String s : objectMap.keySet()) {
            GenTableColumn genTableColumn = genTableColumnMap.get(s);
            if (genTableColumn != null && objectMap.get(s) != null) {
                Object val = objectMap.get(s);
                genTableColumn.setColumnValue(val);
                columns.add(genTableColumn);
            }
        }

        GenTableColumn genTableColumn = genTableColumnMap.get("update_by");
        if (genTableColumn != null) {
            genTableColumn.setColumnValue(SecurityUtils.getUsername());
            columns.add(genTableColumn);
        }
        GenTableColumn updateTimeColumn = genTableColumnMap.get("update_time");
        if (updateTimeColumn != null) {
            updateTimeColumn.setColumnValue(DateUtils.getNowDate());
            columns.add(updateTimeColumn);
        }
        return columns;
    }


    public int update(String tbName, List<ColumnParam> columnQueryList, List<GenTableColumn> columns) {
        return tbMapper.update(tbName, columnQueryList, columns);
    }


    public int updateById(String tbName, JsonMap params, Map<String, GenTableColumn> genTableColumnMap) {
        params.remove("tbName");
        Object idColValue = null;
        List<GenTableColumn> columns = new ArrayList<>();
        for (String s : params.keySet()) {
            GenTableColumn genTableColumn = genTableColumnMap.get(s);
            if (genTableColumn != null && params.get(s) != null) {
                if (!genTableColumn.isHasPermsEdit()) {
                    throw new RuntimeException("权限不足");
                }
                Object val = null;
                switch (genTableColumn.getJavaType()) {
                    case "Integer":
                    case "Long":
                        //为了虚拟列计算  所有数字类型不可为null
                        val = params.getLongVal(s);
                        break;
                    case "BigDecimal":
                        val = params.getBigDecimal(s);
                        break;
                    case "Date":
                        val = StringUtils.isBlank(params.getString(s)) ? null : params.get(s);
                        break;
                    default:
                        val = params.get(s);
                }
                if (genTableColumn.isPk()) {
                    idColValue = val;
                    continue;
                }
                if (genTableColumn.getColumnName().endsWith("price") && val == null) {
                    val = 0;
                }
                genTableColumn.setColumnValue(val);
                columns.add(genTableColumn);
            }
        }
        if (idColValue == null) {
            log.error("id为空 无法更新");
            return 0;
        }
        if (columns.size() == 0) {
            log.error("没有可更新字段 无法更新");
            return 0;
        }

        GenTableColumn genTableColumn = genTableColumnMap.get("update_by");
        if (genTableColumn != null) {
            genTableColumn.setColumnValue(SecurityUtils.getUsername());
            columns.add(genTableColumn);
        }
        GenTableColumn updateTimeColumn = genTableColumnMap.get("update_time");
        if (updateTimeColumn != null) {
            updateTimeColumn.setColumnValue(DateUtils.getNowDate());
            columns.add(updateTimeColumn);
        }

        return tbMapper.updateById(tbName, ID_COLUMN_NAME, idColValue, columns);
    }


    public int addSave(String tbName, JsonMap params, Map<String, GenTableColumn> genTableColumnMap) {
        params.remove("tbName");
        List<String> columnNames = new ArrayList<>();
        List<Object> columnValues = new ArrayList<>();
        for (String s : params.keySet()) {
            GenTableColumn genTableColumn = genTableColumnMap.get(s);
            if (genTableColumn != null && params.get(s) != null) {
                Object val = null;
                switch (genTableColumn.getJavaType()) {
                    case "Integer":
                    case "Long":
                        val = params.getLong(s);
                        break;
                    case "BigDecimal":
                        val = params.getBigDecimal(s);
                        break;
                    default:
                        val = params.get(s);
                }
                columnNames.add(genTableColumn.getColumnName());
                columnValues.add(val);
            }
        }
        if (columnValues.size() == 0) {
            log.error("没有可插入字段 无法新增数据");
            return 0;
        }

        columnNames.add("create_by");
        columnNames.add("update_by");
        columnValues.add(SecurityUtils.getUsername());
        columnValues.add(SecurityUtils.getUsername());
        try {
            return tbMapper.insert(tbName, columnNames, columnValues);
        } catch (DuplicateKeyException e) {
            log.info("DuplicateKeyException ->addSave " + tbName);
            throw new ServiceException("重复操作!");
        } catch (Exception e) {
            throw e;
        }
    }


    public int addHav(String tbName, String col, Long idVal) {
        int i = tbMapper.addHav(tbName, col, 1, ID_COLUMN_NAME, idVal);
        return i;
    }


    public int addHav(String tbName, String col, String idVal) {
        int i = tbMapper.addHav(tbName, col, 1, ID_COLUMN_NAME, idVal);
        return i;
    }


    public int updateByCopyIds(String tbName, String updateColName, String whereColName, String whereValue, Object[] ids) {

        int i = tbMapper.updateByCopyIds(tbName, updateColName, whereColName, whereValue, ids);
        return i;
    }


}